package design.patterns.proxymode.dynamicProxy.controller;

import design.patterns.proxymode.staticProxy.api.IDrive;
import design.patterns.proxymode.staticProxy.api.IWatch;
import design.patterns.proxymode.staticProxy.service.CarStatic;
import design.patterns.proxymode.staticProxy.service.WatchService;
import design.patterns.proxymode.dynamicProxy.service.LogHandler;
import design.patterns.proxymode.dynamicProxy.service.TimHandler;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;

/**
 * JDK动态代理测试类
 * @Description :
 * @author: cww
 * @DateTime: 2018-07-21 11:06
 *
 */

public class JDKTest {

    /**
     * 在carStatic实现中产生一个业务(时间计时)的动态代理drive
     * @param args
     */
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        CarStatic carStatic = new CarStatic();

        //InvocationHandler是一个接口，接口中定义了一个方法invoke。要想实现JDK动态代理，
        //代理类必须继承这个接口
        InvocationHandler h = new TimHandler(carStatic);
        //获取类对象，以便获取类加载器，以及获取类的接口
        Class cls = carStatic.getClass();
        /**
         * newProxyInstance返回代理类的实例，返回后的代理类可以当作被代理类使用
         * （可使用被代理类的接口中声明过的方法）
         * loader:类加载器
         * interfaces:实现接口
         * h：InvocationHandler
         * 返回的是动态代理对象
         */
        IDrive IDrive = (IDrive) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h);
        //调用返回动态代理的drive方法
        IDrive.drive();

        System.out.println();
        System.out.println();
        System.out.println("=====动态代理的简单封装=====");

        WatchService watchService = new WatchService();
        InvocationHandler watchInvoke = new LogHandler(watchService);
        Class aClass = watchService.getClass();
        Object[] watchParam = new Object[]{"管理员","电影"};
        IWatch iWatch = (IWatch)Proxy.newProxyInstance(aClass.getClassLoader(),aClass.getInterfaces(),watchInvoke);
        iWatch.watch(watchParam[1].toString());

        System.out.println();
        System.out.println();
        System.out.println("=====原始动态代理的生成写法=====");
        //生成$Proxy0的class文件
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        //获取动态代理类
        Class proxyClazz = Proxy.getProxyClass(IWatch.class.getClassLoader(),IWatch.class);
        //获得代理类的构造函数，并传入参数类型InvocationHandler.class
        Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
        //通过构造函数来创建动态代理对象，将自定义的InvocationHandler实例传入
        IWatch watch =  (IWatch) constructor.newInstance(new LogHandler(new WatchService()));
        watch.watch("电影");

        System.out.println();
        System.out.println();
        System.out.println("=====将代理生成放入InvocationHandler的实现类中去=====");

        /**
         * 将代理生成放入InvocationHandler的实现类中去
         */
        WatchService watchService1 = new WatchService();
        LogHandler watchInvoke1 = new LogHandler(watchService1);
        IWatch iWatch1 = (IWatch) watchInvoke1.getProxy();
        iWatch1.watch("电影");

        /**
         * 精简
         */

        IWatch iWatch2 = (IWatch) new LogHandler(watchService1).getProxy();
        iWatch2.watch("电影");
    }
}
